package org.groovymud.shell.security.callbacks;

import org.apache.log4j.Logger;
import org.codehaus.groovy.control.CompilationFailedException;
import org.groovymud.object.alive.Player;
import org.groovymud.object.registry.MudCloneException;
import org.groovymud.object.registry.MudObjectAttendant;
import org.groovymud.object.registry.Registry;
import org.groovymud.shell.io.TerminalIO;

import java.io.IOException;
import java.util.Map;

public class ActionCallback implements SelfHandlingCallback {
    private static final Logger logger = Logger.getLogger(ActionCallback.class);

    private final MudObjectAttendant objectLoader;
    private final Registry objectRegistry;

    private final ActionType action;
    private final String objectName;
    private Player player;

    public ActionCallback(String objectName, ActionType action, MudObjectAttendant objectLoader, Registry objectRegistry) {
        this.objectName = objectName;
        this.action = action;
        this.objectLoader = objectLoader;
        this.objectRegistry = objectRegistry;
    }


    public void handle(final TerminalIO terminalIO, final Map<String, Object> callbackData) throws IOException {
        final ActionCallbackCommand actionCallbackCommand = new ActionCallbackCommand() {
            boolean addToCallbackData = true;

            public void load() {
                String username = getObjectName();
                try {
                    player = objectLoader.loadPlayerData(username);
                    if (player != null) {
                        player.getSubject().getPrivateCredentials().add(player.getPlayerCredentials());

                    }
                } catch (Exception e) {
                    logger.error("Failed to load player " + username, e);
                }
            }

            public void create() {
                player = registerNewPlayer(getObjectName(), terminalIO);
            }

            public void checkExists() {
                player = getLoggedInPlayer(getObjectName());
                addToCallbackData = false;
            }

            public void addToCallbackData() {
                if (player != null && addToCallbackData) {
                    callbackData.put("player", player);
                }
            }
        };
        action.handle(actionCallbackCommand);
        actionCallbackCommand.addToCallbackData();

    }

    private Player getLoggedInPlayer(String loggingInPlayerUsername) {
        return (Player) objectRegistry.getMudObject(loggingInPlayerUsername);
    }

    private Player registerNewPlayer(String username, TerminalIO terminalIO) {
        Player player = null;
        try {
            player = objectLoader.cloneAndSetPlayerDetails(username);
            player.setTerminalOutput(terminalIO);
            objectRegistry.register(player);
        } catch (CompilationFailedException e) {
            logger.error(registerPlayerException(username), e);
        } catch (MudCloneException e) {
            logger.error(registerPlayerException(username), e);
        }
        return player;
    }

    private String registerPlayerException(String username) {
        return "Could not register player " + username;
    }


    String getObjectName() {
        return objectName;
    }

    public Player getPlayer() {
        return player;
    }
}
